package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Resource
    private VodConstantProperties vodConstantProperties;

    @Resource
    private AlbumInfoMapper albumInfoMapper;

    @Resource
    private VodService vodService;

    @Resource
    private TrackStatMapper trackStatMapper;

    @Resource
    private UserInfoFeignClient userInfoFeignClient;

    @Resource
    private AlbumStatMapper albumStatMapper;

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {
        //调用云点播API实现声音上传
        // 初始化对象
        VodUploadClient vodUploadClient = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
        //构建请求对象
        VodUploadRequest vodUploadRequest = new VodUploadRequest();
        //设置上传路径
        String path = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        vodUploadRequest.setMediaFilePath(path);
        // 调用上传功能
        try {
            VodUploadResponse response = vodUploadClient.upload(vodConstantProperties.getRegion(), vodUploadRequest);
            log.info("Upload FileId = {}", response.getFileId());
            //  调用数据万象进行声音审核!
            //	创建map 集合
            HashMap<String, Object> map = new HashMap<>();
            map.put("mediaFileId", response.getFileId());
            map.put("mediaUrl", response.getMediaUrl());
            //	返回数据
            return map;
        } catch (Exception e) {
            // 业务方进行异常处理
            log.error("Upload Err", e);
        }
        return Map.of();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        // track_info  创建对象
        TrackInfo trackInfo = new TrackInfo();
        // 属性赋值
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 用户ID
        trackInfo.setUserId(userId);
        // order_num  用于表示声音的顺修 等同于album_info.include_track_count + 1
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        // media_duration media_file_id media_url media_size media_type;
        // 调用 VOD API 获得真实数据
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        //赋值 属性
        trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfoMapper.insert(trackInfo);

        // track_stat  声音统计信息
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
        // album_info  include_track_count  + 1
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);
    }

    public void saveTrackStat(Long trackId, String statType) {
        // track_stat  创建对象
        TrackStat trackStat = new TrackStat();
        // 属性赋值
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(new Random().nextInt(100000));
        // 保存
        trackStatMapper.insert(trackStat);
    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.selectUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    @Override
    public void removeTrackInfo(Long trackId) {
        // 获得声音对象
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        // 一共需要删除几张表中的数据
        // track_info track_stat album_info.include_track_count - 1; vod
        // 删除track_info
        trackInfoMapper.deleteById(trackId);
        // 删除track_stat
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        // 减少album_info表中的  album_info.include_track_count - 1
        // 获取专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
        //处理声音序列号
        trackInfoMapper.updateOrderNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());

        // 删除云点播的数据
        vodService.deleteMedia(trackInfo.getMediaFileId());
    }

    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        // 修改声音对象
        TrackInfo trackInfo = this.getById(trackId);
        // 获得之前的流媒体ID
        String oldMediaFileId = trackInfo.getMediaFileId();
        // 属性拷贝 copy
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 考虑如何修改了流媒体的数据
        // 新的流媒体ID
        String newMediaFileId = trackInfoVo.getMediaFileId();
        // 判断两次流媒体ID 是否一致
        if (!oldMediaFileId.equals(newMediaFileId)) {
            // 获得最新的数据
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(newMediaFileId);
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());

            // 删除就得流媒体的数据
            vodService.deleteMedia(oldMediaFileId);
        }

        // 修改
        trackInfoMapper.updateById(trackInfo);
    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> trackListPage, Long albumId, Long userId) {
        //  专辑类型 相关
        //  用户身份相关
        //  免费试听集数(专辑付费时才有)
        //1.  先查询一共有多少条声音
        IPage<AlbumTrackListVo> pageInfo = trackInfoMapper.selectAlbumTrackPage(trackListPage, albumId);
        //  根据专辑ID获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //2.  判断此用户is是否为空
        if (null == userId) {
            // 未登录  需要判断专辑类型  除免费专辑之外 都需要将付费标识设置为true(试听集数除外)
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
                // 寻找试听集数为多少 order_num 大于试听集数的数据字段 设置为true
                pageInfo.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
                        .forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
            }
            // 数据返回
            return pageInfo;
        }
        // 用户ID 不为空
        if (null != userId) {
            // 判断专辑类型
            //  声明一个变量  看是否需要进行付费
            boolean isNeedPayBalance = false;
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
                //  vip 免费   判断用户身份
                Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
                Assert.notNull(userInfoVoResult, "远程调用用户服务获取用户数据失败");
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                Assert.notNull(userInfoVo, "远程调用用户服务获取用户数据userInfoVo失败");
                // 不是vip 或者 vip 已经过期
                if (0 == userInfoVo.getIsVip() || (1 == userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))) {
                    // 进行付费  掏钱牢底
                    isNeedPayBalance = true;
                }
            } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
                //  付费 牢底
                isNeedPayBalance = false;
            }
            //  判断付费情况
            if (isNeedPayBalance) {
                // 当前专辑的哪些声音需要付费 出去免费试听的集数
                // 用户是否购买过专辑 或者购买过专辑里面的某些声音
                List<AlbumTrackListVo> albumTrackListNeedPaidList = pageInfo.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()).toList();
                List<Long> trackNeedPaidIdList = albumTrackListNeedPaidList.stream().map(AlbumTrackListVo::getTrackId).toList();
                // 远程调用 map.put(trackId,1)不需要购买;   map.put(trackId,0)未购买需要购买
                // todo:13:45分钟
                Result<Map<Long, Integer>> userIsPaidTrack = userInfoFeignClient.userIsPaidTrack(albumId, trackNeedPaidIdList);
                Assert.notNull(userIsPaidTrack, "远程调用用户服务获取用户数据失败");
                // map.put(trackId,1)不需要购买;   map.put(trackId,0)未购买需要购买
                Map<Long, Integer> map = userIsPaidTrack.getData();
                for (AlbumTrackListVo albumTrackListVo : albumTrackListNeedPaidList) {
                    // true   false

//                   boolean isShowPaidMark = map.get(albumTrackListVo.getTrackId()) == 1 ? albumTrackListVo.setIsShowPaidMark(false) : albumTrackListVo.setIsShowPaidMark(true);
//                    boolean falg = map.get(albumTrackListVo.getTrackId()) == 1 ? false : true;
                    albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0);
                }
            }
        }
        // 返回数据
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
        try {
            // 更新对应声音的播放量
            trackStatMapper.updateTrackStat(trackStatMqVo.getTrackId(), trackStatMqVo.getCount(), trackStatMqVo.getStatType());
            //更新声音所对应的专辑的播放量
            albumStatMapper.updateAlbumStat(trackStatMqVo.getAlbumId(), trackStatMqVo.getCount(), SystemConstant.ALBUM_STAT_PLAY);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
        // 新建一个List集合用于数据存储 并最终返回
        List<Map<String, Object>> list = new ArrayList<>();
        // 查询用户购买的声音列表
        // 1.用声音ID 查询专辑id
        TrackInfo trackInfo = this.getById(trackId);
        Long albumId = trackInfo.getAlbumId();
        // 2.用专辑ID 查询需要购买的声音列表
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        // 因为需要购买时都是点击购买 所以只需要查询trackId>当前点击的声音id即可 当然也可以用 orderNum>当前点击声音的orderNum
        // todo:
        LambdaQueryWrapper<TrackInfo> trackInfoLambdaQueryWrapper = new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, albumId).gt(TrackInfo::getId, trackId);
        // 需要付费的声音列表
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(trackInfoLambdaQueryWrapper);
        // 3.获取用户已经购买过的声音列表
        Result<List<Long>> trackIdListResul = userInfoFeignClient.findUserPaidTrackList(albumId);
        Assert.notNull(trackIdListResul, "远程调用用户服务获取用户数据失败");
        List<Long> trackIdList = trackIdListResul.getData();
        // 4. 两个集合做差集就是最终需要付费的声音列表
        // 使用stream流的差集操作 filter过滤进行操作
        List<TrackInfo> infoList = trackInfoList.stream().filter(trackInfo1 -> !trackIdList.contains(trackInfo1.getId())).collect(Collectors.toList());
        //  本集(点击的哪一集); 后10集(包含>= 不包含>); 后20集;
//        if (infoList.size() >= 0) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            map.put("name", "本集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice());
//            //  购买集数;
//            map.put("trackCount", 0);
//            //  添加到集合中;
//            list.add(map);
//        }
//        //  后10集；后n集; 10以内;
//        if (infoList.size() > 0 && infoList.size() <= 10) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            int count = infoList.size();
//            map.put("name", "后" + count + "集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count))));
//            //  购买集数;
//            map.put("trackCount", count);
//            //  添加到集合中;
//            list.add(map);
//        }
//        //  一定会显示后10集;
//        if (infoList.size() > 10) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            //  后10集
//            map.put("name", "后10集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf("10"))));
//            //  购买集数;
//            map.put("trackCount", 10);
//            //  添加到集合中;
//            list.add(map);
//        }
//        //  后20集；后n集; 20以内;
//        if (infoList.size() > 10 && infoList.size() <= 20) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            int count = infoList.size();
//            map.put("name", "后" + count + "集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count))));
//            //  购买集数;
//            map.put("trackCount", count);
//            //  添加到集合中;
//            list.add(map);
//        }
//        //  一定会显示后10集;
//        if (infoList.size() > 20) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            //  后10集
//            map.put("name", "后20集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf("20"))));
//            //  购买集数;
//            map.put("trackCount", 20);
//            //  添加到集合中;
//            list.add(map);
//        }
//        //  后20集；后n集; 20以内;
//        if (infoList.size() > 20 && infoList.size() <= 30) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            int count = infoList.size();
//            map.put("name", "后" + count + "集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count))));
//            //  购买集数;
//            map.put("trackCount", count);
//            //  添加到集合中;
//            list.add(map);
//        }
//        //  一定会显示后30集;
//        if (infoList.size() > 30) {
//            //  构建本集操作;
//            Map<String, Object> map = new HashMap<>();
//            //  后10集
//            map.put("name", "后30集");
//            //  声音的价格; 由专辑来决定;
//            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf("30"))));
//            //  购买集数;
//            map.put("trackCount", 30);
//            //  添加到集合中;
//            list.add(map);
//        }

        // 处理“本集”
        if (infoList.size() >= 0) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "本集");
            map.put("price", albumInfo.getPrice());
            map.put("trackCount", 0); // 假设“本集”是单个音频文件，所以计数为0
            list.add(map);
        }

        // 定义固定的步长数组
        int[] steps = {10, 20, 30};
        for (int step : steps) {
            if (infoList.size() > step) {
                Map<String, Object> map = new HashMap<>();
                map.put("name", "后" + step + "集");
                map.put("price", albumInfo.getPrice().multiply(new BigDecimal(step)));
                map.put("trackCount", step);
                list.add(map);
            } else if (infoList.size() <= step && infoList.size() > 0) {
                Map<String, Object> map = new HashMap<>();
                map.put("name", "后" + infoList.size() + "集");
                map.put("price", albumInfo.getPrice().multiply(new BigDecimal(infoList.size())));
                map.put("trackCount", infoList.size());
                list.add(map);
                break; // 如果找到了合适的范围，则退出循环
            }
        }
        return list;
    }

    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount, Long userId) {
        //声明一个集合
        List<TrackInfo> trackInfoList = new ArrayList<>();
        // 获取专辑ID
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        // 获取用户已经购买的集合
        Result<List<Long>> trackInfoIdListResult = userInfoFeignClient.findUserPaidTrackList(albumId);
        Assert.notNull(trackInfoIdListResult, "获取用户已经购买的声音ID集合失败");
        // 获取到已经购买的声音ID集合
        List<Long> trackInfoIdListData = trackInfoIdListResult.getData();
        if (trackCount > 0) {
            LambdaQueryWrapper<TrackInfo> trackInfoLambdaQueryWrapper = new LambdaQueryWrapper<TrackInfo>();
            trackInfoLambdaQueryWrapper.eq(TrackInfo::getAlbumId, albumId).gt(TrackInfo::getId, trackId);
            if (trackInfoIdListData.size() > 0) {
                // 排除已经购买的声音ID集合
                trackInfoLambdaQueryWrapper.notIn(TrackInfo::getId, trackInfoIdListData);
            }
            // 展示多少条
            trackInfoLambdaQueryWrapper.last("limit " + trackCount);
            // 获取数据
            trackInfoList = trackInfoMapper.selectList(trackInfoLambdaQueryWrapper);
        } else {
            //  返回本集 trackInfoList
            if (trackInfoIdListData.contains(trackId)){
                return new ArrayList<>();
            }
            trackInfoList.add(trackInfo);
        }
        // 返回数据
        return trackInfoList;
    }
}
